<template>
  <ul class="tree">
    <li v-for="node in nodes" :key="node.id || node.categoryCode" class="tree-item">
      <div class="tree-row" :class="{ active: selectedId === node.id }" @click.stop="handleSelect(node)">
        <span
          class="toggle"
          v-if="hasChildren(node)"
          :class="{ expanded: isExpanded(node.id) }"
          @click.stop="toggle(node.id)"
        >
          {{ isExpanded(node.id) ? '▼' : '▶' }}
        </span>
        <span class="toggle" v-else></span>
        <span class="label">{{ node.categoryName }}</span>
      </div>
      <transition name="fade">
        <CategoryTree
          v-if="hasChildren(node) && isExpanded(node.id)"
          :nodes="node.children"
          :selected-id="selectedId"
          @select="emitSelect"
        />
      </transition>
    </li>
  </ul>
</template>

<script setup>
import { ref, watch } from 'vue'

const props = defineProps({
  nodes: { type: Array, default: () => [] },
  selectedId: { type: [Number, String, null], default: null },
  // 默认展开层级（含该层级），例如 2 表示根和二级都展开
  defaultExpandDepth: { type: Number, default: 2 }
})

const emit = defineEmits(['select'])
const expanded = ref(new Set())
const depthMap = ref(new Map())

function hasChildren(node) {
  return Array.isArray(node.children) && node.children.length > 0
}

function isExpanded(id) {
  return expanded.value.has(id)
}

function toggle(id) {
  const depth = depthMap.value.get(id)
  if (depth && depth <= props.defaultExpandDepth) return
  if (expanded.value.has(id)) expanded.value.delete(id)
  else expanded.value.add(id)
}

function handleSelect(node) {
  emit('select', node)
}

function emitSelect(node) {
  emit('select', node)
}

function buildDepthAndExpand(list, depth) {
  if (!Array.isArray(list)) return
  for (const n of list) {
    if (n && n.id != null) {
      depthMap.value.set(n.id, depth)
      if (depth <= props.defaultExpandDepth && hasChildren(n)) {
        expanded.value.add(n.id)
      }
    }
    if (hasChildren(n)) buildDepthAndExpand(n.children, depth + 1)
  }
}

watch(
  () => props.nodes,
  (val) => {
    expanded.value = new Set()
    depthMap.value = new Map()
    buildDepthAndExpand(val, 1)
  },
  { immediate: true, deep: true }
)
</script>

<style scoped>
.tree {
  list-style: none;
  padding-left: 8px;
  margin: 0;
}

.tree-item {
  margin: 2px 0;
}

.tree-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: 8px;
  cursor: pointer;
  color: #374151;
  transition: background-color .15s ease, color .15s ease;
}

.tree-row.active {
  background: #e8f0fe;
  color: #2563eb;
  font-weight: 600;
}

.tree-row:hover { background: #f8fafc; }

.toggle {
  width: 16px;
  text-align: center;
  color: #9ca3af;
}

.toggle.expanded { color: #6b7280; }

.label {
  flex: 1;
}

.tree .tree {
  margin-left: 8px;
  border-left: 1px dashed #e5e7eb;
}

.fade-enter-active, .fade-leave-active { transition: opacity .15s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>


